package com.smart.community.region.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.smart.community.commons.utils.SecurityUtils;
import com.smart.community.region.dto.PropertyCompanyBuildingTypeDTO;
import com.smart.community.region.entity.PropertyCompanyBuildingType;
import com.smart.community.region.mapper.PropertyCompanyBuildingTypeMapper;
import com.smart.community.region.service.IBuildingTypeCategoryService;
import com.smart.community.region.service.IPropertyCompanyBuildingTypeService;
import com.smart.community.region.vo.BuildingTypeCategoryVO;
import com.smart.community.region.vo.PropertyCompanyBuildingTypeVO;

import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;

/**
 * 物业公司建筑类型Service实现类
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 */
@Slf4j
@Service
public class PropertyCompanyBuildingTypeServiceImpl extends ServiceImpl<PropertyCompanyBuildingTypeMapper, PropertyCompanyBuildingType> implements IPropertyCompanyBuildingTypeService {

    @Autowired
    private PropertyCompanyBuildingTypeMapper propertyCompanyBuildingTypeMapper;

    @Autowired
    private IBuildingTypeCategoryService buildingTypeCategoryService;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = "property:building:type", allEntries = true)
    public void createBuildingType(PropertyCompanyBuildingTypeDTO buildingTypeDTO) {
        // 检查编码是否重复
        if (isCodeDuplicate(buildingTypeDTO.getPropertyCompanyId(), 
                buildingTypeDTO.getBuildingTypeCode(), null)) {
            throw new IllegalArgumentException("建筑类型编码重复");
        }

        // 转换为实体
        PropertyCompanyBuildingType entity = convertToEntity(buildingTypeDTO);
        
        // 设置创建信息
        Long currentUserId = SecurityUtils.getCurrentUserId();
        entity.setCreateBy(currentUserId);
        entity.setUpdateBy(currentUserId);

        // 保存
        int result = propertyCompanyBuildingTypeMapper.insert(entity);
        if (result <= 0) {
            throw new RuntimeException("创建建筑类型失败");
        }
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = "property:building:type", allEntries = true)
    public void batchCreateBuildingType(List<PropertyCompanyBuildingTypeDTO> buildingTypeDTOs) {
        for (PropertyCompanyBuildingTypeDTO dto : buildingTypeDTOs) {
            createBuildingType(dto);
        }
    }

    @Override
    @Cacheable(value = "property:building:type:list", key = "#propertyCompanyId + ':' + #page.current + ':' + #page.size", unless = "#result == null || #result.getRecords().isEmpty()")
    public IPage<PropertyCompanyBuildingTypeVO> getBuildingTypeList(Long propertyCompanyId, 
                                                                   Page<PropertyCompanyBuildingTypeVO> page) {
        long startTime = System.currentTimeMillis();
        log.info("获取物业公司建筑类型列表，物业公司ID：{}，页码：{}，大小：{}", 
                propertyCompanyId, page.getCurrent(), page.getSize());
        try {
            Page<PropertyCompanyBuildingType> entityPage = new Page<>(page.getCurrent(), page.getSize());
            IPage<PropertyCompanyBuildingType> entityResult = propertyCompanyBuildingTypeMapper.selectPageByCondition(
                    entityPage, propertyCompanyId, null, null, null);
            
            IPage<PropertyCompanyBuildingTypeVO> result = convertToVOPage(entityResult);
            long endTime = System.currentTimeMillis();
            log.info("获取物业公司建筑类型列表成功，耗时：{}ms", endTime - startTime);
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("获取物业公司建筑类型列表失败，物业公司ID：{}，耗时：{}ms", propertyCompanyId, endTime - startTime, e);
            return new Page<>();
        }
    }

    @Override
    @Cacheable(value = "property:building:type:condition", key = "#propertyCompanyId + ':' + #buildingTypeName + ':' + #buildingTypeCode + ':' + #status + ':' + #page.current + ':' + #page.size", unless = "#result == null || #result.getRecords().isEmpty()")
    public IPage<PropertyCompanyBuildingTypeVO> getBuildingTypeListByCondition(Long propertyCompanyId,
                                                                              String buildingTypeName,
                                                                              String buildingTypeCode,
                                                                              Integer status,
                                                                              Page<PropertyCompanyBuildingTypeVO> page) {
        long startTime = System.currentTimeMillis();
        log.info("根据条件分页查询建筑类型，物业公司ID：{}，建筑类型名称：{}，建筑类型编码：{}，状态：{}", 
                propertyCompanyId, buildingTypeName, buildingTypeCode, status);
        try {
            Page<PropertyCompanyBuildingType> entityPage = new Page<>(page.getCurrent(), page.getSize());
            IPage<PropertyCompanyBuildingType> entityResult = propertyCompanyBuildingTypeMapper.selectPageByCondition(
                    entityPage, propertyCompanyId, buildingTypeName, buildingTypeCode, status);
            
            IPage<PropertyCompanyBuildingTypeVO> result = convertToVOPage(entityResult);
            long endTime = System.currentTimeMillis();
            log.info("根据条件分页查询建筑类型成功，耗时：{}ms", endTime - startTime);
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("根据条件分页查询建筑类型失败，物业公司ID：{}，耗时：{}ms", propertyCompanyId, endTime - startTime, e);
            return new Page<>();
        }
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = "property:building:type", allEntries = true)
    public void updateBuildingType(PropertyCompanyBuildingTypeDTO buildingTypeDTO) {
        // 检查编码是否重复
        if (isCodeDuplicate(buildingTypeDTO.getPropertyCompanyId(), 
                buildingTypeDTO.getBuildingTypeCode(), buildingTypeDTO.getId())) {
            throw new IllegalArgumentException("建筑类型编码重复");
        }

        // 获取原实体
        PropertyCompanyBuildingType originalEntity = propertyCompanyBuildingTypeMapper.selectById(buildingTypeDTO.getId());
        if (originalEntity == null) {
            throw new IllegalArgumentException("建筑类型不存在");
        }

        // 转换为实体
        PropertyCompanyBuildingType entity = convertToEntity(buildingTypeDTO);
        
        // 设置更新信息
        Long currentUserId = SecurityUtils.getCurrentUserId();
        entity.setUpdateBy(currentUserId);
        entity.setCreateBy(originalEntity.getCreateBy());

        // 更新
        int result = propertyCompanyBuildingTypeMapper.updateById(entity);
        if (result <= 0) {
            throw new RuntimeException("更新建筑类型失败");
        }
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = "property:building:type", allEntries = true)
    public boolean deleteBuildingType(Long id) {
        log.info("删除建筑类型，ID：{}", id);
        try {
            int result = propertyCompanyBuildingTypeMapper.deleteById(id);
            return result > 0;
        } catch (Exception e) {
            log.error("删除建筑类型失败，ID：{}", id, e);
            return false;
        }
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = "property:building:type", allEntries = true)
    public boolean batchDeleteBuildingType(List<Long> ids) {
        log.info("批量删除建筑类型，ID列表：{}", ids);
        try {
            for (Long id : ids) {
                if (!deleteBuildingType(id)) {
                    return false;
                }
            }
            return true;
        } catch (Exception e) {
            log.error("批量删除建筑类型失败，ID列表：{}", ids, e);
            return false;
        }
    }

    @Override
    @Cacheable(value = "property:building:type:detail", key = "#id", unless = "#result == null")
    public PropertyCompanyBuildingTypeVO getBuildingTypeDetail(Long id) {
        long startTime = System.currentTimeMillis();
        log.info("获取建筑类型详情，ID：{}", id);
        try {
            PropertyCompanyBuildingType entity = propertyCompanyBuildingTypeMapper.selectById(id);
            if (entity == null) {
                return null;
            }
            PropertyCompanyBuildingTypeVO result = convertToVO(entity);
            long endTime = System.currentTimeMillis();
            log.info("获取建筑类型详情成功，耗时：{}ms", endTime - startTime);
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("获取建筑类型详情失败，ID：{}，耗时：{}ms", id, endTime - startTime, e);
            return null;
        }
    }

    @Override
    @Cacheable(value = "property:building:type:company", key = "#propertyCompanyId", unless = "#result == null || #result.isEmpty()")
    public List<PropertyCompanyBuildingTypeVO> getBuildingTypesByPropertyCompanyId(Long propertyCompanyId) {
        long startTime = System.currentTimeMillis();
        log.info("根据物业公司ID获取建筑类型列表，物业公司ID：{}", propertyCompanyId);
        try {
            List<PropertyCompanyBuildingType> entities = propertyCompanyBuildingTypeMapper.selectByPropertyCompanyId(propertyCompanyId);
            List<PropertyCompanyBuildingTypeVO> result = convertToVOList(entities);
            long endTime = System.currentTimeMillis();
            log.info("根据物业公司ID获取建筑类型列表成功，耗时：{}ms", endTime - startTime);
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("根据物业公司ID获取建筑类型列表失败，物业公司ID：{}，耗时：{}ms", propertyCompanyId, endTime - startTime, e);
            return new ArrayList<>();
        }
    }

    @Override
    @Cacheable(value = "property:building:type:check", key = "#propertyCompanyId + ':' + #buildingTypeCode + ':' + #excludeId", unless = "#result == false")
    public boolean isCodeDuplicate(Long propertyCompanyId, String buildingTypeCode, Long excludeId) {
        log.info("检查建筑类型编码是否重复，物业公司ID：{}，编码：{}，排除ID：{}", propertyCompanyId, buildingTypeCode, excludeId);
        try {
            int count = propertyCompanyBuildingTypeMapper.checkCodeDuplicate(propertyCompanyId, buildingTypeCode, excludeId);
            return count > 0;
        } catch (Exception e) {
            log.error("检查建筑类型编码是否重复失败，物业公司ID：{}，编码：{}", propertyCompanyId, buildingTypeCode, e);
            return false;
        }
    }

    @Override
    @Cacheable(value = "property:building:type:public:condition", key = "#buildingTypeName + ':' + #buildingTypeCode + ':' + #status + ':' + #page.current + ':' + #page.size", unless = "#result == null || #result.getRecords().isEmpty()")
    public IPage<PropertyCompanyBuildingTypeVO> getPublicBuildingTypeListByCondition(String buildingTypeName,
                                                                                     String buildingTypeCode,
                                                                                     Integer status,
                                                                                     Page<PropertyCompanyBuildingTypeVO> page) {
        long startTime = System.currentTimeMillis();
        log.info("分页查询平台公共建筑类型列表，建筑类型名称：{}，建筑类型编码：{}，状态：{}", 
                buildingTypeName, buildingTypeCode, status);
        try {
            Page<PropertyCompanyBuildingType> entityPage = new Page<>(page.getCurrent(), page.getSize());
            IPage<PropertyCompanyBuildingType> entityResult = propertyCompanyBuildingTypeMapper.selectPublicBuildingTypePage(
                    entityPage, buildingTypeName, buildingTypeCode, status);
            
            IPage<PropertyCompanyBuildingTypeVO> result = convertToVOPage(entityResult);
            long endTime = System.currentTimeMillis();
            log.info("分页查询平台公共建筑类型列表成功，耗时：{}ms", endTime - startTime);
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("分页查询平台公共建筑类型列表失败，耗时：{}ms", endTime - startTime, e);
            return new Page<>();
        }
    }

    @Override
    @Cacheable(value = "property:building:type:public:all", key = "'all'", unless = "#result == null || #result.isEmpty()")
    public List<PropertyCompanyBuildingTypeVO> getPublicBuildingTypes() {
        long startTime = System.currentTimeMillis();
        log.info("获取平台公共建筑类型列表");
        try {
            List<PropertyCompanyBuildingType> entities = propertyCompanyBuildingTypeMapper.selectPublicBuildingTypes();
            List<PropertyCompanyBuildingTypeVO> result = convertToVOList(entities);
            long endTime = System.currentTimeMillis();
            log.info("获取平台公共建筑类型列表成功，耗时：{}ms", endTime - startTime);
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("获取平台公共建筑类型列表失败，耗时：{}ms", endTime - startTime, e);
            return new ArrayList<>();
        }
    }

    /**
     * 转换为实体
     */
    private PropertyCompanyBuildingType convertToEntity(PropertyCompanyBuildingTypeDTO dto) {
        PropertyCompanyBuildingType entity = new PropertyCompanyBuildingType();
        BeanUtils.copyProperties(dto, entity);
        
        // 转换分类ID列表为JSON字符串
        if (!CollectionUtils.isEmpty(dto.getCategoryIds())) {
            try {
                entity.setCategoryIds(objectMapper.writeValueAsString(dto.getCategoryIds()));
            } catch (Exception e) {
                log.error("转换分类ID列表为JSON失败", e);
                entity.setCategoryIds("[]");
            }
        }
        
        return entity;
    }

    /**
     * 转换为VO
     */
    private PropertyCompanyBuildingTypeVO convertToVO(PropertyCompanyBuildingType entity) {
        PropertyCompanyBuildingTypeVO vo = new PropertyCompanyBuildingTypeVO();
        BeanUtils.copyProperties(entity, vo);
        
        // 转换JSON字符串为分类ID列表
        if (StringUtils.hasText(entity.getCategoryIds())) {
            try {
                List<Long> categoryIds = objectMapper.readValue(entity.getCategoryIds(), 
                        new TypeReference<List<Long>>() {});
                vo.setCategoryIds(categoryIds);
                
                // 获取分类名称列表
                if (!CollectionUtils.isEmpty(categoryIds)) {
                    List<BuildingTypeCategoryVO> categories = buildingTypeCategoryService.getTypeListByIds(categoryIds);
                    List<String> categoryNames = categories.stream()
                            .map(BuildingTypeCategoryVO::getCategoryName)
                            .collect(Collectors.toList());
                    vo.setCategoryNames(categoryNames);
                }
            } catch (Exception e) {
                log.error("转换JSON字符串为分类ID列表失败", e);
                vo.setCategoryIds(new ArrayList<>());
                vo.setCategoryNames(new ArrayList<>());
            }
        }
        
        return vo;
    }

    /**
     * 转换为VO列表
     */
    private List<PropertyCompanyBuildingTypeVO> convertToVOList(List<PropertyCompanyBuildingType> entities) {
        if (CollectionUtils.isEmpty(entities)) {
            return new ArrayList<>();
        }
        
        return entities.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    /**
     * 转换为VO分页
     */
    private IPage<PropertyCompanyBuildingTypeVO> convertToVOPage(IPage<PropertyCompanyBuildingType> entityPage) {
        Page<PropertyCompanyBuildingTypeVO> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize());
        voPage.setTotal(entityPage.getTotal());
        voPage.setPages(entityPage.getPages());
        
        List<PropertyCompanyBuildingTypeVO> voList = convertToVOList(entityPage.getRecords());
        voPage.setRecords(voList);
        
        return voPage;
    }
}
